// X86Translator.cpp, // Implement class X86Translator
#include "arch/x86/X86Translator.h"
#include "arch/x86/X86.h"
#include "crossbit/VBlock.h"
#include "crossbit/VInst.h"
#include "crossbit/TBlock.h"
#include "crossbit/Exit.h"
#include "crossbit/RegAllocator.h"
#include "crossbit/ProcessorState.h"

using namespace crossbit;

struct X86Translator::RegisterFile X86Translator::saved; 

		X86Translator::X86Translator(ProcessorState *state, RegAllocator *alloc) 
:Translator(state), reg_allocator(alloc), first_time(true), /* spillPool(NULL),*/ inst(NULL) ,fp_word_count(0),fp_dword_count(0)
{
		// tblock related initialization is done in "initTranslation"
		// spillPool = (XTInt32 *)malloc(100 * sizeof(XTInt32));
		// memset((void *)spillPool, 0, 100 * sizeof(XTInt32));
}

X86Translator::~X86Translator()
{
		// if (spillPool)
		//	free(spillPool);

		//added by zhengjuyu
		//set the fpu control word to under flow
}

void X86Translator::initTranslation() 
{

		// before start to translate, the translator should provide the callback functions
		// for the reg allocator, pass these params to initialize the reg allocator

		inst_buf = tblock->enterAddr();

		X86::setP(tblock->enterAddr());

		// save the esp value, for the first time
		X86::movwRegToMem(X86::ESP, (XTMemAddr)&saved_esp);
#if 0
		if(first_time) {
				first_time = false;
				X86::movwRegToMem(X86::ESP, (XTMemAddr)&saved_esp);
		}
#endif
}


XTRegNum X86Translator::X86RegAlloc(XTRegNum vreg, RegAccessMode mode)
{
		XTRegNum alloc = reg_allocator->regAlloc(vreg, mode);

		if (alloc == X86::ESP)
		{
				dirty_esp = true;
		}

		return alloc;
}

XTRegNum X86Translator::X86RegAllocForce(XTRegNum vreg, XTRegNum expect, RegAccessMode mode)
{
		XTRegNum alloc = reg_allocator->regAllocForce(vreg, expect, mode);

		if (alloc == X86::ESP)
		{
				dirty_esp = true;
		}

		return alloc;
}

XTRegNum X86Translator::X86RegAllocForceExcept(XTRegNum vreg, XTRegNum except, RegAccessMode mode)
{
		XTRegNum alloc = reg_allocator->regAllocForceExcept(vreg, except, mode);

		if (alloc == X86::ESP)
		{
				dirty_esp = true;
		}

		return alloc;
}


void X86Translator::X86RegAllocReserve(XTRegNum treg)
{
		reg_allocator->regAllocReserve(treg);
}

void X86Translator::X86RegAllocRelease(XTRegNum treg)
{
		reg_allocator->regAllocRelease(treg);
}


void X86Translator::setBlockStub()
{

		//TODO
		//X86::movImmToMem((XTMemAddr)vblock, (XTMemAddr)(&GLOBAL::vblock_stub), WORD);
		X86::movImmToMem((XTMemAddr)tblock, (XTMemAddr)(&GLOBAL::tblock_stub), WORD);

		//Added by suntingtao
		// test whether the current tblock is a super block , if not , increase it's 
		//'run_count' counter, if the value arrive the threshold of a super block it ret directly.
		if( !tblock -> isSupperBlock() ){
				X86::movwMemToReg( tblock -> getRunCountAddr() , X86::EAX );
				X86::inc( X86::EAX );
				X86::cmpImmWithReg( GLOBAL::THRESHOLD , X86::EAX ); 	 

				//if THRESHOLD > EAX , jump to the next third instruction
				X86::jccRelativeDirectDisp32( 8 , X86::LE );  

				X86::movbImmToMem( 1 , (XTMemAddr)(&GLOBAL::BUILD_SUPER_BLOCK));
				X86::ret();

				X86::movwRegToMem( X86::EAX , tblock -> getRunCountAddr());

		}

}

// we implement a lightweight x86 encoder
void X86Translator::encode(VBlock *vb, TBlock *tb)
{
		this->vblock = vb;
		this->tblock = tb;


		initTranslation();

		reg_allocator->init(vb);

		// 1. Instruction selection
		//
		// Currently, we trivially do any work for "instruction selection":
		// each VInst is encoded into x86 codes individually,
		// resulting in poor quality of generated code, yet simplifying the job of encoder
		// and also reducing the runtime overhead caused by sophisticated instruction
		// selection algorithms.
		//

		// usageCount();

		setBlockStub();

		// 3. Encode
		for (VBlock::vb_iterator it = vblock->begin(); it != vblock->end(); ++it, reg_allocator->incrementVinstSeq()) {
				inst = *it;
				Opcode op = inst->getOpcode();

				switch (op) {
						case OP_GET:
																		printf("GET\n");   
																	 encodeGET();    break;
						case OP_PUT: 
																		printf("PUT\n");
															   encodePUT();    break;
						case OP_LD:
																	printf("LD\n");	   
																 encodeLD();	    break;
						case OP_ST:
																	printf("ST\n");	   
																 encodeST();	    break;
						case OP_LI:
																	printf("LI\n");	   
																 encodeLI();	    break;
						case OP_MOV:
																	printf("MOV\n");   
																 encodeMOV();    break;

						case OP_SEXT:  
																 printf("SEXIT\n");
																 encodeSEXT();   break;
						case OP_ZEXT:
														  printf("ZEXT\n");
																 encodeZEXT();   break;
						case OP_ADD:
																	printf("ADD\n");
													    encodeADD();    break; 
						case OP_SUB:   
																 printf("SUB\n");
																 encodeSUB();    break;
						case OP_AND:  
															  printf("AND\n");
																 encodeAND();    break; 
						case OP_XOR:   
																	printf("XOR\n");
																 encodeXOR();    break; 
						case OP_OR:	   
																 printf("OR\n");
																 encodeOR();	    break;
						case OP_NOT:
																	printf("NOT\n");
													    encodeNOT();    break;
						case OP_SLL:
																 printf("SLL\n");
													    encodeSLL();    break;   
						case OP_SRL: 
															 	printf("SRL\n");
														   encodeSRL();    break;
						case OP_SRA:
																 printf("SRA\n");
													    encodeSRA();    break;
						/*
						   case OP_SLLV:   encodeSLLV();   break;
						   case OP_SRLV:   encodeSRLV();   break;
						   case OP_SRAV:   encodeSRAV();   break;
						 */
						case OP_MUL:  
															 printf("MUL\n");
															 encodeMUL();    break; 
						case OP_MULU:
															 printf("MULU\n");
														  encodeMULU();   break;
						case OP_DIV:
																printf("DIV\n");
												    encodeDIV();    break;
						case OP_DIVU:
															 printf("DIVU\n");
													   encodeDIVU();   break;

						case OP_CMP:
															 printf("CMP\n");
												    encodeCMP();    break;
						case OP_BRANCH:
																printf("BRANCH\n");
															 encodeBRANCH();    break;
						case OP_JMP:
															 printf("JMP\n");
												    encodeJMP();    break;
						case OP_HALT:
															 printf("HALT\n");
													   encodeSBREAK(); break;
						case OP_SYSCALL:
																printf("SYSCALL\n");
																encodeSYSCALL();break;
						case OP_CALL:
																printf("CALL\n");
													   encodeCALL();   break;

						/*
						   newadd folat instructions
						 */
						case OP_FPUT_S:  
																printf("FPUTS\n");
															 encodeFPUTS();   break;
						case OP_FGET_S:
																printf("FGETS\n");
													   encodeFGETS();   break;
						case OP_FPUT_D:
																printf("FPUTD\n");
													   encodeFPUTD();   break;
						case OP_FGET_D: 
																printf("FGETD\n");
														  encodeFGETD();   break;

						case OP_FLD:
																printf("FLD\n");
													   encodeFLD();   break;
						case OP_FST:
																printf("FST\n");
													   encodeFST();   break;

						case OP_FMOV:
																printf("FMOV\n");
													   encodeFMOV();    break;

						case OP_FADD_S:
																printf("FADDS\n");
												    encodeFADDS();    break;
						case OP_FADD_D:
																printf("FADDD\n");
												    encodeFADDD();    break;
						case OP_FSUB_S:  
																printf("FSUB\n");
														  encodeFSUBS();    break;
						case OP_FSUB_D:   
                printf("FSUB\n");
															 encodeFSUBD();    break;
						case OP_FMUL_S: 
																printf("FMULS\n");
													   encodeFMULS();    break;
						case OP_FMUL_D:
															 printf("FMULD\n");
												    encodeFMULD();    break;
						case OP_FDIV_S:  
															 printf("FDIVS\n");
														  encodeFDIVS();    break;
						case OP_FDIV_D:
															 printf("FDIVD\n");
												    encodeFDIVD();    break;
						case OP_FNEG_S: 
																printf("FNEGS\n");
													   encodeFNEGS();    break;
						case OP_FNEG_D:
																printf("FNEGD\n");
												    encodeFNEGD();    break;
						case OP_FABS_S:
															 printf("FABSS\n");
												    encodeFABSS();    break;
						case OP_FABS_D: 
																printf("FABSD\n");
													   encodeFABSD();    break;
						case OP_FSQRT_S:
																printf("FSQRTS\n");
												    encodeFSQRTS();    break;
						case OP_FSQRT_D:
																printf("FSQRTD\n");
												    encodeFSQRTD();    break;
						case OP_FCMP_S:  
																printf("FCMPS\n");
														  encodeFCMPS();    break;
						case OP_FCMP_D:   
																printf("FCMPD\n");	
															 encodeFCMPD();    break;
						case OP_FCONV: 
															 printf("FCONV\n");
													   encodeFCONV();    break;
						case OP_FINCSTP:
																printf("FINCSTP\n");
															 encodeFINCSTP();	break;


						default:
										 assert(0 && "Unrecognized opcode");
				}
		}


		// add Into-ExecEngine jump and END_OF_BLOCK exit 
		// if the last instruction is not unconditional jump
		if ( ! (inst->getOpcode() == OP_JMP)) 
				endOfBlock();

		//encode all the TBlock Exits
		encodeExits();

		// set target code block size
		tblock->setSize(X86::getP() - inst_buf);
}

void X86Translator::endOfBlock()
{
		X86::jmpRelativeDirectDisp32(0);	// displacement will be back-patched later
		XTInt32 i = addTBlockExit(ExitReason::ENDOFBLOCK, 
						vblock->nextSPC(),	
						X86::getP() - 4 - inst_buf,
						NULL);
		Exit& e = tblock->getExit(i);

		e.link_type = LinkType::DIRECT;

}

XTInt32 X86Translator::addTBlockExit(XTInt32 why, XTMemAddr next, XTInt32 exitOffset, VInst *inst)
{
		Exit exit;
		exit.why = why;
		exit.next = next;
		exit.exitOffset = exitOffset;
		exit.inst = inst;
		exit.linked = 0;
		exit.linkCode = NULL;
		exit.dest = 0;
		return tblock->addExit(exit);
}

#if 0
TBlock *X86Translator::headBlock()
{
		class X86HeadTBlock : public TBlock {
				public:
						X86HeadTBlock()
								:TBlock((XTMemAddr)(new XTInt8[11 /* see below */]))
								{
								}

						~X86HeadTBlock()
						{
								delete [] (XTInt8*)(tb_tcode);
						}
		};

		tblock = new X86HeadTBlock();

		X86::setP(reinterpret_cast<XTPStr>(tblock->enterAddr()));

		// We want to assign the "return address" to ReturnAddress.
		// The return address is pushed to stack when this function is called,
		// so we just have to copy the value currently on the top of the stack 
		// to ReturnAddress. The assembly is as follows:
		//
		// [2] mov    %esp,%eax
		// [2] mov    (%eax),%eax
		// [6] mov    %eax,&ReturnAddress
		// [1] ret
		//
		// Exactly 11 bytes.

		X86::movwRegToReg(X86::ESP, X86::EAX);
		X86::movwMemToReg(X86::EAX, X86::EAX);
		X86::movwRegToMem(X86::EAX, (XTMemAddr)&GLOBAL::return_address);
		X86::ret();

		addTBlockExit(ExitReason::HEAD, (XTMemAddr)0, 0, NULL);

		return tblock;
}
#endif

void X86Translator::encodeExits()
{
		//added by Zheng, Juyu
		//for debugging purpose
		if( tblock->exitNums() == 0 )
				endOfBlock();

		for (XTInt32 i = 0, num = tblock->exitNums(); i < num; ++i) {
				Exit &e = tblock->getExit(i);
				*(XTInt32 *)(inst_buf + e.exitOffset) = X86::getP() - (inst_buf + e.exitOffset + 4);

				// restore ESP and ret
				//XXX
				if (dirty_esp) 
				{
						X86::movwMemToReg((XTMemAddr)(&saved_esp), X86::ESP); 
				}
				//added by suntingtao
			    if( e.link_type == LinkType::DIRECT ){
						e.linkCode = (XTInt8*)X86::getP();
				}		

				// mov i<which Exit>, &TBlock::lastExit_
				// jmp rel32
				X86::movwImmToMem(i, (XTMemAddr)&GLOBAL::last_exit);

				if( e.link_type == LinkType::INDIRECT ){  
						// modified by suntingtao , only indirect trace linking need save the e.next
						//mov e.next to edx, for indirect trace linking
						X86::movwMemToReg((XTMemAddr)(&e.next), X86::EDX);
						e.linkCode = (XTInt8*)X86::getP();
				} 

				X86::ret();
				//added by zhengjuyu, reserve 5 words for nop
				X86::putWord(0x90909090);
				X86::nop();

				// tblock->addRelocationPoint((X86::getP() - 4)- inst_buf);
		}
}

void X86Translator::encodeGET()
{
		// DEBUG(std::cerr << "  Encoding GET" << std::endl);
		// GET s, v
		XTMemAddr addr = src_state->get(inst->getOperand(1).reg);
		XTRegNum reg = inst->getOperand(2).reg;
		//assert(reg != 0);

		X86::movwMemToReg(addr, X86RegAlloc(reg, DEF));
}

// PUT v, s
void X86Translator::encodePUT()
{
		// DEBUG(std::cerr << "  Encoding PUT" << std::endl);
		XTRegNum reg = inst->getOperand(1).reg;
		XTMemAddr addr = src_state->get(inst->getOperand(2).reg);

		if (reg == 0)
				X86::movwImmToMem(reg, addr);
		else
		{
				X86::movwRegToMem(X86RegAlloc(reg, USE), addr);
		}
}

// LI imm, v
void X86Translator::encodeLI()
{
		// DEBUG(std::cerr << "  Encoding LI" << std::endl);
		XTInt32 imm = inst->getOperand(1).imm;
		XTRegNum reg = inst->getOperand(2).reg;
		assert(reg != 0);

		X86::movwImmToReg(imm, X86RegAlloc(reg, DEF));
}

// LD addr, sz, v
void X86Translator::encodeLD()
{
		XTRegNum	reg	= inst->getOperand(1).reg;
		XTInt32	disp	= inst->getOperand(2).imm;
		BlockSize	size	= inst->getOperand(3).size;
		XTRegNum	dst	= inst->getOperand(4).reg;

		assert(dst != 0);

		XTRegNum Tdst;
		XTRegNum Tsrc;

		//				X86RegAllocReserve(X86::ESP);
		//				X86RegAllocReserve(X86::EBP);

		if( size == BYTE )
		{
				Tdst = X86RegAllocForce(dst, X86::EBX, DEF);
				//			Tdst = X86RegAlloc(dst ,DEF); // modified by stt
				if( reg != 0 ){
						//		if( dst == reg ) printf("Oh MY god\n");
						Tsrc = X86RegAllocForceExcept( reg, X86::ESP, USE );
				}
				if (reg == 0)
						X86::movMemToReg((XTMemAddr)disp, size, Tdst);
				else
						X86::movMemToReg( Tsrc, disp, size, Tdst);

		}
		else
		{
				if( reg != 0 )
						Tsrc = X86RegAllocForceExcept( reg, X86::ESP, USE );

				if (size == BYTE)
				{
						// TODO: find a better solution
						Tdst = X86RegAllocForce(dst, X86::EBX, DEF);
				}
				else
						Tdst = X86RegAlloc(dst, DEF);

				if (reg == 0)
						X86::movMemToReg((XTMemAddr)disp, size, Tdst);
				else
						X86::movMemToReg( Tsrc, disp, size, Tdst);
		}

		//				X86RegAllocRelease(X86::EBP);
		//				X86RegAllocRelease(X86::ESP);
}
// ST v, sz, addr
void X86Translator::encodeST()
{
		XTRegNum	src	= inst->getOperand(1).reg;
		BlockSize	size	= inst->getOperand(2).size;
		XTRegNum	reg	= inst->getOperand(3).reg;
		XTInt32	disp	= inst->getOperand(4).imm;

		//				X86RegAllocReserve(X86::ESP);
		//				X86RegAllocReserve(X86::EBP);

		if (src == 0) {
				if (reg == 0)
						X86::movImmToMem(src, disp, size);
				else {
						XTRegNum Treg = X86RegAllocForceExcept(reg, X86::ESP, USE);
						X86::movImmToMem(src, Treg, disp, size);
				}
		}
		else {
				XTRegNum Tsrc;
				if (size == BYTE)
						// TODO: find a better solution
						Tsrc = X86RegAllocForce(src, X86::EBX, USE);
				else
						Tsrc = X86RegAlloc(src, USE);

				if (reg == 0)
						X86::movRegToMem(Tsrc, size, (XTMemAddr)disp);
				else {
						XTRegNum Treg = X86RegAllocForceExcept(reg, X86::ESP, USE);
						assert(Treg != X86::ESP);
						X86::movRegToMem(Tsrc, size, Treg, disp);
				}
		}

		//				X86RegAllocRelease(X86::EBP);
		//				X86RegAllocRelease(X86::ESP);
}

// MOV v, v
void X86Translator::encodeMOV()
{
		XTRegNum src = inst->getOperand(1).reg;
		XTRegNum dst = inst->getOperand(2).reg;

		assert(dst != 0);

		if (src == 0)
				X86::movwImmToReg(0, X86RegAlloc(dst, DEF));
		else
		{
				XTRegNum Tsrc = X86RegAlloc(src, USE);
				X86::movwRegToReg( Tsrc, X86RegAlloc(dst, DEF));
		}
}

// SEXT v, sz, v
void X86Translator::encodeSEXT()
{
		XTRegNum src = inst->getOperand(1).reg,
				 Tsrc = X86RegAlloc(src, USE);
		BlockSize sz = inst->getOperand(2).size;
		XTRegNum dst = inst->getOperand(3).reg,
				 Tdst = X86RegAlloc(dst, DEF);

		// It makes nosense src to be v0
		assert(src != 0 && dst != 0);

		if (sz == BYTE)
				X86::movsblRegToReg(Tsrc, Tdst);
		else if (sz == HALFWORD)
				X86::movswlRegToReg(Tsrc, Tdst);
		else
				assert(0);
}

// ZEXT v, sz, v
void X86Translator::encodeZEXT()
{
		XTRegNum src = inst->getOperand(1).reg,
				 Tsrc = X86RegAlloc(src, USE);
		BlockSize sz = inst->getOperand(2).size;
		XTRegNum dst = inst->getOperand(3).reg,
				 Tdst = X86RegAlloc(dst, DEF);

		// It makes nosense src to be v0, v1
		assert(src != 0 && dst != 0);
		if (sz == BYTE)
				X86::movzblRegToReg(Tsrc, Tdst);
		else if (sz == HALFWORD)
				X86::movzwlRegToReg(Tsrc, Tdst);
		else
				assert(0);
}

// ADD v, v, v
void X86Translator::encodeADD()
{
		// DEBUG(std::cerr << "  Encoding ADD" << std::endl);
		XTRegNum src1 = inst->getOperand(1).reg;
		XTRegNum src2 = inst->getOperand(2).reg;
		XTRegNum dst	= inst->getOperand(3).reg;

		// temp soluation for this
		if (dst == 0)
				return;
		//assert(dst != 0);

		if (src1 == 0 && src2 == 0)
		{
				XTRegNum Tdst = X86RegAlloc(dst, DEF);
				X86::movwImmToReg(0, Tdst);
		}
		else if (src1 == 0) {
				XTRegNum Tsrc2 = X86RegAlloc(src2, USE);
				XTRegNum Tdst = X86RegAlloc(dst, DEF);
				if (src2 != dst)
						X86::movwRegToReg(Tsrc2, Tdst);
		} 
		else if (src2 == 0) {
				XTRegNum Tsrc1 = X86RegAlloc(src1, USE);
				XTRegNum Tdst = X86RegAlloc(dst, DEF);
				if (src1 != dst)
						X86::movwRegToReg(Tsrc1, Tdst);
		} 
		else {
				XTRegNum Tsrc1 = X86RegAlloc(src1, USE);
				XTRegNum Tsrc2 = X86RegAlloc(src2, USE);
				XTRegNum Tdst = X86RegAlloc(dst, DEF);

				if (src1 == dst)
						X86::addRegToReg(Tsrc2, Tdst);
				else if (src2 == dst)
						X86::addRegToReg(Tsrc1, Tdst);
				else {
						X86::movwRegToReg(Tsrc1, Tdst);
						X86::addRegToReg(Tsrc2, Tdst); 
				}
		}
}

// SUB v, v, v
void X86Translator::encodeSUB()
{
		// DEBUG(std::cerr << "  Encoding SUB" << std::endl);
		XTRegNum src1 = inst->getOperand(1).reg;
		XTRegNum src2 = inst->getOperand(2).reg;
		XTRegNum dst	= inst->getOperand(3).reg;

		assert(dst != 0);
		assert(!(src1 == 0 && src2 == 0));

		if (src1 == 0) {
				XTRegNum Tsrc2 = X86RegAlloc(src2, USE);
				XTRegNum Tdst = X86RegAlloc(dst, DEF);
				if (src2 != dst)
						X86::movwRegToReg(Tsrc2, Tdst);
				X86::negReg(Tdst);
		}
		else if (src2 == 0) {
				XTRegNum Tsrc1 = X86RegAlloc(src1, USE);
				XTRegNum Tdst = X86RegAlloc(dst, DEF);
				if (src1 != dst)
						X86::movwRegToReg(Tsrc1, Tdst);
		}
		else {
				XTRegNum Tsrc1 = X86RegAlloc(src1, USE);
				XTRegNum Tsrc2 = X86RegAlloc(src2, USE);
				XTRegNum Tdst = X86RegAlloc(dst, DEF);

				if (src1 == dst) 
						X86::subRegFromReg(Tsrc2, Tsrc1);
				else if (src2 == dst)
				{
						X86::subRegFromReg(Tsrc1, Tsrc2);
						X86::negReg(Tsrc2);
				}
				else {
						X86::movwRegToReg(Tsrc1, Tdst);
						X86::subRegFromReg(Tsrc2, Tdst);
				}
		}

}

// AND v, v, v
void X86Translator::encodeAND()
{
		// DEBUG(std::cerr << "  Encoding AND" << std::endl);
		XTRegNum src1 = inst->getOperand(1).reg;
		XTRegNum src2 = inst->getOperand(2).reg;
		XTRegNum dst	= inst->getOperand(3).reg;

		assert(dst != 0);
		// It makes nosense src1 and src2 to be
		// v0 at the same time.
		assert(! (src1 == 0 && src2 == 0));

		if (src1 == 0 || src2 == 0) {
				// 0 & ANY -> 0
				XTRegNum Tdst = X86RegAlloc(dst, DEF);
				X86::movwImmToReg(0, Tdst);
		} 
		else {
				XTRegNum Tsrc1 = X86RegAlloc(src1, USE);
				XTRegNum Tsrc2 = X86RegAlloc(src2, USE);
				XTRegNum Tdst = X86RegAlloc(dst, DEF);

				if (src1 == dst)
						X86::andRegToReg(Tsrc2, Tdst);
				else if (src2 == dst)
						X86::andRegToReg(Tsrc1, Tdst);
				else { X86::movwRegToReg(Tsrc1, Tdst);
						X86::andRegToReg(Tsrc2, Tdst); 
				} 
		} 
} 

// XOR v, v, v 
void X86Translator::encodeXOR()
{
		// DEBUG(std::cerr << "  Encoding XOR" << std::endl);
		XTRegNum src1 = inst->getOperand(1).reg;
		XTRegNum src2 = inst->getOperand(2).reg;
		XTRegNum dst	= inst->getOperand(3).reg;

		assert(dst != 0);
		// It makes nosense src1 and src2 to be
		// v0 at the same time.
		assert(! (src1 == 0 && src2 == 0));

		if (src1 == 0) {
				// 0 ^ ANY -> ANY
				XTRegNum Tsrc2 = X86RegAlloc(src2, USE);
				XTRegNum Tdst = X86RegAlloc(dst, DEF);
				if (src1 != dst)
						X86::movwRegToReg(Tsrc2, Tdst);
		} 
		else if (src2 == 0) {
				// ANY ^ 0 -> ANY
				XTRegNum Tsrc1 = X86RegAlloc(src1, USE);
				XTRegNum Tdst = X86RegAlloc(dst, DEF);
				if (src1 != dst)
						X86::movwRegToReg(Tsrc1, Tdst);
		} 
		else {
				XTRegNum Tsrc1 = X86RegAlloc(src1, USE);
				XTRegNum Tsrc2 = X86RegAlloc(src2, USE);
				XTRegNum Tdst = X86RegAlloc(dst, DEF);

				if (src1 == dst)
						X86::xorRegToReg(Tsrc2, Tdst);
				else if (src2 == dst)
						X86::xorRegToReg(Tsrc1, Tdst);
				else {
						X86::movwRegToReg(Tsrc1, Tdst);
						X86::xorRegToReg(Tsrc2, Tdst); 
				}
		}
}

// OR v, v, v
void X86Translator::encodeOR()
{
		XTRegNum src1 = inst->getOperand(1).reg;
		XTRegNum src2 = inst->getOperand(2).reg;
		XTRegNum dst	= inst->getOperand(3).reg;

		assert(dst != 0);
		// It makes nosense src1 and src2 to be
		// v0 at the same time.
		assert(! (src1 == 0 && src2 == 0));

		if (src1 == 0) {
				// 0 | ANY -> ANY
				XTRegNum Tsrc2 = X86RegAlloc(src2, USE);
				XTRegNum Tdst = X86RegAlloc(dst, DEF);

				if (src2 != dst)
						X86::movwRegToReg(Tsrc2, Tdst);
		} 
		else if (src2 == 0) {
				// ANY | 0 -> ANY
				XTRegNum Tsrc1 = X86RegAlloc(src1, USE);
				XTRegNum Tdst = X86RegAlloc(dst, DEF);

				if (src1 != dst)
						X86::movwRegToReg(Tsrc1, Tdst);
		} 
		else {
				XTRegNum Tsrc1 = X86RegAlloc(src1, USE);
				XTRegNum Tsrc2 = X86RegAlloc(src2, USE);
				XTRegNum Tdst = X86RegAlloc(dst, DEF);

				if (src1 == dst)
						X86::orRegToReg(Tsrc2, Tdst);
				else if (src2 == dst)
						X86::orRegToReg(Tsrc1, Tdst);
				else {
						X86::movwRegToReg(Tsrc1, Tdst);
						X86::orRegToReg(Tsrc2, Tdst); 
				}
		}
}

// NOT v, v
void X86Translator::encodeNOT()
{
		XTRegNum src = inst->getOperand(1).reg,
				 dst = inst->getOperand(2).reg;

		assert(src != 0 && dst != 0);

		XTRegNum Tsrc = X86RegAlloc(src, USE), 
				 Tdst = X86RegAlloc(dst, DEF);

		if (src != 0) {
				if (src != dst)
						X86::movwRegToReg(Tsrc, Tdst);
				X86::notReg(Tdst);
		}
		else
				X86::movwImmToReg(0xffffffff, Tdst);
}

/*
// SLL v, imm, v
void X86Translator::encodeSLL()
{
XTRegNum src = inst->getOperand(1).reg,
dst = inst->getOperand(3).reg;
unsigned XTUint8 shc = inst->getOperand(2).imm;

assert(src != 0 && dst != 0);

XTRegNum Tsrc = regAlloc(src, USE),
Tdst = regAlloc(dst, DEF);

if (src != dst)
X86::movwRegToReg(Tsrc, Tdst);
X86::shlReg_by_imm(Tdst, shc);
}
 */

// SLL v, v, v
void X86Translator::encodeSLL()
{
		XTRegNum src = inst->getOperand(1).reg,
				 dst = inst->getOperand(3).reg,
				 shc = inst->getOperand(2).reg;

		assert(src != 0 && dst != 0 && shc != 0);

		// the allocation sequence is important:
		// shc must be allocated before src&dst, so that
		// src&dst will not use ECX
		X86RegAllocForce(shc, X86::ECX, USE);
		XTRegNum Tsrc = X86RegAlloc(src, USE),
				 Tdst = X86RegAlloc(dst, DEF);

		if (src != dst) {
				X86::movwRegToReg(Tsrc, Tdst);
		}
		X86::shlRegByCl(Tdst);
}

/*
// SRL v, imm, v
void X86Translator::encodeSRL()
{
XTRegNum src = inst->getOperand(1).reg,
dst = inst->getOperand(3).reg;
unsigned XTUint8 shc = inst->getOperand(2).imm;

assert(src != 0 && dst != 0);

XTRegNum Tsrc = regAlloc(src, USE),
Tdst = regAlloc(dst, DEF);

if (src != dst) 
X86::movwRegToReg(Tsrc, Tdst);
X86::shrReg_by_imm(Tdst, shc);
}
 */

// SRL v, v, v
void X86Translator::encodeSRL()
{
		XTRegNum src = inst->getOperand(1).reg,
				 dst = inst->getOperand(3).reg,
				 shc = inst->getOperand(2).reg;

		assert(src != 0 && dst != 0 && shc != 0);

		X86RegAllocForce(shc, X86::ECX, USE);
		XTRegNum Tsrc = X86RegAlloc(src, USE),
				 Tdst = X86RegAlloc(dst, DEF);

		if (src != dst)
				X86::movwRegToReg(Tsrc, Tdst);
		X86::shrRegByCl(Tdst);
}

/*
// SRA v, imm, v
void X86Translator::encodeSRA()
{
XTRegNum src = inst->getOperand(1).reg,
dst = inst->getOperand(3).reg;
unsigned XTUint8 shc = inst->getOperand(2).imm;

assert(src != 0 && dst != 0);

XTRegNum Tsrc = regAlloc(src, USE),
Tdst = regAlloc(dst, DEF);

if (src != dst)
X86::movwRegToReg(Tsrc, Tdst);
X86::sarReg_by_imm(Tdst, shc);
}
 */

// SRLV src, shc, dst
void X86Translator::encodeSRA()
{
		XTRegNum src = inst->getOperand(1).reg,
				 dst = inst->getOperand(3).reg,
				 shc = inst->getOperand(2).reg;

		assert(src != 0 && dst != 0 && shc != 0);

		X86RegAllocForce(shc, X86::ECX, USE);
		XTRegNum Tsrc = X86RegAlloc(src, USE),
				 Tdst = X86RegAlloc(dst, DEF);

		if (src != dst)
				X86::movwRegToReg(Tsrc, Tdst);
		X86::sarRegByCl(Tdst);
}

// MUL src1, src2, dst1(hi), dst2(lo)
void X86Translator::encodeMUL()
{
		X86RegAllocReserve(X86::EAX);
		X86RegAllocReserve(X86::EDX);

		XTRegNum src1 = inst->getOperand(1).reg,
				 src2 = inst->getOperand(2).reg,
				 dst1 = inst->getOperand(3).reg,
				 dst2 = inst->getOperand(4).reg;

		// simplify the situation
		assert(src1 != 0 &&
						src2 != 0 &&
						dst1 != 0 &&
						dst2 != 0 );

		XTRegNum Tsrc1 = X86RegAlloc(src1, USE),
				 Tsrc2 = X86RegAlloc(src2, USE),
				 Tdst1 = X86RegAlloc(dst1, DEF),
				 Tdst2 = X86RegAlloc(dst2, DEF);

		// EDX  :EAX  <- EAX  * reg
		// dst1 :dst2 <- src1 * src2
		X86::movwRegToReg(Tsrc1, X86::EAX);
		X86::imulEaxToReg(Tsrc2);
		X86::movwRegToReg(X86::EDX, Tdst1);
		X86::movwRegToReg(X86::EAX, Tdst2);

		X86RegAllocRelease(X86::EDX);
		X86RegAllocRelease(X86::EAX);
}

// MULU v, v, v, v
void X86Translator::encodeMULU()
{
		X86RegAllocReserve(X86::EAX);
		X86RegAllocReserve(X86::EDX);

		XTRegNum src1 = inst->getOperand(1).reg,
				 src2 = inst->getOperand(2).reg,
				 dst1 = inst->getOperand(3).reg,
				 dst2 = inst->getOperand(4).reg;

		// simplify the situation
		assert(src1 != 0 &&
						src2 != 0 &&
						dst1 != 0 &&
						dst2 != 0 );

		XTRegNum Tsrc1 = X86RegAlloc(src1, USE),
				 Tsrc2 = X86RegAlloc(src2, USE),
				 Tdst1 = X86RegAlloc(dst1, DEF),
				 Tdst2 = X86RegAlloc(dst2, DEF);

		// EDX  :EAX  <- EAX  * reg
		// dst1 :dst2 <- src1 * src2
		X86::movwRegToReg(Tsrc1, X86::EAX);
		X86::mulEaxToReg(Tsrc2);
		X86::movwRegToReg(X86::EDX, Tdst1);
		X86::movwRegToReg(X86::EAX, Tdst2);

		X86RegAllocRelease(X86::EDX);
		X86RegAllocRelease(X86::EAX);
}

// DIV v, v, v, v
void X86Translator::encodeDIV()
{
		X86RegAllocReserve(X86::EAX);
		X86RegAllocReserve(X86::EDX);

		XTRegNum src1 = inst->getOperand(1).reg,
				 src2 = inst->getOperand(2).reg,
				 dst1 = inst->getOperand(3).reg,
				 dst2 = inst->getOperand(4).reg;

		assert(src1 != 0 &&
						src2 != 0 &&
						dst1 != 0 &&
						dst2 != 0 );

		XTRegNum Tsrc1 = X86RegAlloc(src1, USE),
				 Tsrc2 = X86RegAlloc(src2, USE),
				 Tdst1 = X86RegAlloc(dst1, DEF),
				 Tdst2 = X86RegAlloc(dst2, DEF);

		// EAX(quotient):EDX(remainder) <- EDX:EAX / reg
		// dst1         :dst2           <- src1    / src2
		X86::movwRegToReg(Tsrc1, X86::EAX);
		X86::movwRegToReg(X86::EAX, X86::EDX);
		X86::andImmToReg(0x80000000, X86::EDX);
		X86::sarRegByImm(X86::EDX, 31);
		X86::idivEdxEaxByReg(Tsrc2);
		X86::movwRegToReg(X86::EAX, Tdst1);
		X86::movwRegToReg(X86::EDX, Tdst2);

		X86RegAllocRelease(X86::EDX);
		X86RegAllocRelease(X86::EAX);
}

// DIVU v, v, v, v
void X86Translator::encodeDIVU()
{
		X86RegAllocReserve(X86::EAX);
		X86RegAllocReserve(X86::EDX);

		XTRegNum src1 = inst->getOperand(1).reg,
				 src2 = inst->getOperand(2).reg,
				 dst1 = inst->getOperand(3).reg,
				 dst2 = inst->getOperand(4).reg;

		assert(src1 != 0 &&
						src2 != 0 &&
						dst1 != 0 &&
						dst2 != 0 );

		XTRegNum Tsrc1 = X86RegAlloc(src1, USE),
				 Tsrc2 = X86RegAlloc(src2, USE),
				 Tdst1 = X86RegAlloc(dst1, DEF),
				 Tdst2 = X86RegAlloc(dst2, DEF);

		// EAX(quotient):EDX(remainder) <- EDX:EAX / reg
		// dst1         :dst2           <- src1    / src2
		X86::movwRegToReg(Tsrc1, X86::EAX);
		X86::movwImmToReg(0, X86::EDX);
		X86::divEdxEaxByReg(Tsrc2);
		X86::movwRegToReg(X86::EAX, Tdst1);
		X86::movwRegToReg(X86::EDX, Tdst2);

		X86RegAllocRelease(X86::EDX);
		X86RegAllocRelease(X86::EAX);
}

// CMP cc, v1, v2, v3
void X86Translator::encodeCMP()
{    
		XTRegNum src1 = inst->getOperand(2).reg,
				 src2 = inst->getOperand(3).reg,
				 dst	= inst->getOperand(4).reg;

		assert(dst != 0);

		XTRegNum Tsrc1, Tsrc2,
				 // got a problem here, x86::setcc only support r/m8 register.
				 // this is a workaround, any better solution? TODO
				 // FIXME: crash if force use X86::EAX
				 Tdst = X86RegAllocForce(dst, X86::EBX, DEF); // Modified by suntingtao

		// zero Tdst
		//deleted by zhengjuyu
		//X86::xorRegToReg(Tdst, Tdst);

		XTUint8 tttn = X86::CCENCODINGS[inst->getOperand(1).cc];

		if (src1 == 0) {
				//Tsrc1 = regAlloc(src1, USE);
				X86RegAllocReserve( X86::EAX );
				Tsrc2 = X86RegAlloc(src2, USE);
				X86::xorRegToReg(X86::EAX, X86::EAX);
				X86::cmpRegWithReg(X86::EAX, Tsrc2);
				X86RegAllocRelease( X86::EAX );
				//X86::cmp_imm_withReg(src1, Tsrc2);
		}
		else if (src2 == 0) {
				Tsrc1 = X86RegAlloc(src1, USE);
				X86::testRegWithReg(Tsrc1, Tsrc1);
		}
		else {  
				Tsrc1 = X86RegAlloc(src1, USE);
				Tsrc2 = X86RegAlloc(src2, USE);
				X86::cmpRegWithReg(Tsrc1, Tsrc2);
		}

		X86::setcc(Tdst, tttn);
		//added by zhengjuyu
		X86::movzblRegToReg(Tdst, Tdst);
}

// BRANCH cc, v1, v2, reg, disp
void X86Translator::encodeBRANCH()
{

		XTInt32 i = addTBlockExit(
						ExitReason::BRANCHTAKEN, 
						0,	// next: filled in at runtime 
						0,	// exitOffset: set later
						inst);
		Exit& e = tblock->getExit(i);

		// fill in exit.next
		XTRegNum reg	= inst->getOperand(4).reg;
		XTInt32   disp	= inst->getOperand(5).imm;
		if (reg == 0){ 
				e.link_type = LinkType :: DIRECT;
				e.next = disp; 
		}
		else {
				e.link_type = LinkType :: INDIRECT;
				X86::movwImmToMem(disp, (XTMemAddr) &(e.next));
				X86::addRegToMem(X86RegAlloc(reg, USE), (XTMemAddr) &(e.next));
		}

		// conditional branch
		CmpCC cc = inst->getOperand(1).cc;
		XTRegNum src1 = inst->getOperand(2).reg,
				 src2 = inst->getOperand(3).reg;

		XTRegNum Tsrc1, Tsrc2;
		if (src1 == 0) {
				Tsrc2 = X86RegAlloc(src2, USE);
				X86::cmpImmWithReg(src1, Tsrc2);
		}
		else if (src2 == 0) {
				Tsrc1 = X86RegAlloc(src1, USE);
				X86::testRegWithReg(Tsrc1, Tsrc1);
		}
		else {
				Tsrc1 = X86RegAlloc(src1, USE);
				Tsrc2 = X86RegAlloc(src2, USE);
				X86::cmpRegWithReg(Tsrc1, Tsrc2);
		}

		XTUint8 tttn = X86::CCENCODINGS[cc];
		X86::jccRelativeDirectDisp32(0, tttn);    // back patched later

		// set exit offset
		e.exitOffset = X86::getP() - 4 - inst_buf;
}


// JMP pc
void X86Translator::encodeJMP()
{
		XTInt32 i = addTBlockExit(
						ExitReason::BRANCHTAKEN, 
						0,	// next: filled in at runtime 
						0,	// exitOffset: set later
						inst);

		Exit& e = tblock->getExit(i);

		XTRegNum  reg	    = inst->getOperand(1).reg;
		XTInt32    disp    = inst->getOperand(2).imm;

		if (reg == 0){
				//Added by suntingtao, to support linking for super block
				e.link_type = LinkType::DIRECT;
				e.next = disp;
		} else {
				// register value is evaluated at runtime
				// fill in exit.next
				e.link_type = LinkType::INDIRECT;
				X86::movwImmToMem(disp, (XTMemAddr) &(e.next));
				X86::addRegToMem(X86RegAlloc(reg, USE), (XTMemAddr) &(e.next));
		}

		X86::jmpRelativeDirectDisp32(0);    // back patched later

		// set exit offset
		e.exitOffset = X86::getP() - 4 - inst_buf;
}

// SYSCALL code
// For platforms with same OS, SYSCALL does not have to exit the current
// TBlock, otherwise we have to exit, to emulate the syscall.
void X86Translator::encodeSYSCALL()
{
		// For SimpleScalar platform, we have to exit the current tblock.

		X86::jmpRelativeDirectDisp32(0);	// back patched later

		XTInt32 i = addTBlockExit(ExitReason::SYSCALLEXIT,
						vblock->nextSPC(),		// next
						X86::getP() - 4 - inst_buf,	// exitOffset
						inst);
		Exit& e = tblock -> getExit(i);			
		e.link_type = LinkType::NOLINK;
}

void X86Translator::encodeSBREAK()
{
		X86::sbreak();
#ifdef DEBUG
		tblock->addBreakpoint( inst->getVAddr(), X86::getP() - 1 ); 
#endif
}

void X86Translator::encodeCALL()
{
		XTInt32 addr = inst->getOperand(1).word;
		XTInt32 num = (XTInt32) inst->getOperand(2).word;	// arguments number

		// XTInt32 *sp = &call_stack[1023];
		XTMemAddr sp = (XTMemAddr)call_stack + sizeof(call_stack) - sizeof(XTInt32);

		X86::movwRegToMem(X86::ESP, sp);		// save old ESP
		X86::movwImmToReg(sp, X86::ESP);		// use simulated stack

		// save EAX, EDX, ECX, according to x86 function calling ABI
		// these three registers should be saved by caller
		X86::pushReg(X86::EAX);
		X86::pushReg(X86::EDX);
		X86::pushReg(X86::ECX);

		// push function arguments from RIGHT to LEFT
		for (XTInt32 i = num + 2; i > 2; i--) {
				XTRegNum reg = inst->getOperand(i).reg;
				X86::pushReg( X86RegAlloc(reg, USE) );
		}

		X86::callRelativeDirectDisp32(addr - (XTInt32)(X86::getP() + 5));
		tblock->addRelocationPoint((X86::getP() - 4) - inst_buf);

		// pop the function arguments
		X86::addImmToReg(num * sizeof(XTInt32), X86::ESP);

		// restore EAX, EDX, ECX
		X86::popReg(X86::ECX);
		X86::popReg(X86::EDX);
		X86::popReg(X86::EAX);

		// restore ESP
		X86::popReg(X86::ESP);
}

// float point encoding added
void X86Translator::encodeFPUTS(){
		XTMemAddr addr = src_state->fpGet(inst->getOperand(1).reg);
		X86::fpPopFreg32(addr);
}

void X86Translator::encodeFGETS(){
		XTMemAddr addr = src_state->fpGet(inst->getOperand(1).reg);
		X86::fpPushFreg32(addr);
}

void X86Translator::encodeFPUTD(){
		XTMemAddr addr = src_state->fpGet(inst->getOperand(1).reg);
		X86::fpPopFreg64(addr);
}

void X86Translator::encodeFGETD(){
		XTMemAddr addr = src_state->fpGet(inst->getOperand(1).reg);
		X86::fpPushFreg64(addr);
}

void X86Translator::encodeFLD(){
		XTRegNum	reg	= inst->getOperand(1).reg;
		XTInt32	disp	= inst->getOperand(2).imm;
		BlockSize	size	= inst->getOperand(3).size;
		XTRegNum	dst	= inst->getOperand(4).reg;

		// notice: float-point registers are stack-based and 
		// can not apply register allocation police. This FLD
		// instruction will cause a memToMem copy operation.
		// XTMemAddr addr = src_state->reg(reg) + disp;
		if(size == WORD){
				//X86::fpPushFreg32(addr);
				XTMemAddr dst_addr = src_state->fpGet(dst);
				X86RegAllocReserve( X86::ECX );

				if( reg != 0 )
				{
						XTRegNum srcreg = X86RegAllocForceExcept( reg, X86::ESP, USE );
						X86::movMemToReg(srcreg, disp, size, X86::ECX);
						X86::movRegToMem( X86::ECX, size, dst_addr); 
				}
				else
				{
						X86::movwMemToReg((XTMemAddr)disp, X86::ECX);
						X86::movRegToMem( X86::ECX, size, dst_addr); 
				}
				X86RegAllocRelease( X86::ECX );
		}
		else{
				//X86::fpPushFreg64(addr);
				XTMemAddr dst_addr = src_state->fpGet(dst);
				X86RegAllocReserve( X86::ECX );

				if( reg != 0 )
				{
						XTRegNum srcreg = X86RegAllocForceExcept( reg, X86::ESP, USE );
						X86::movMemToReg( srcreg, disp, WORD, X86::ECX );
						X86::movRegToMem( X86::ECX, WORD, dst_addr);
						X86::movMemToReg( srcreg, disp + 4, WORD, X86::ECX );
						X86::movRegToMem( X86::ECX, WORD, dst_addr + 4);
				}
				else 
				{
						X86::movwMemToReg( (XTMemAddr)disp, X86::ECX );
						X86::movRegToMem( X86::ECX, WORD, dst_addr );
						X86::movwMemToReg( (XTMemAddr)(disp + 4), X86::ECX );
						X86::movRegToMem( X86::ECX, WORD, dst_addr+4);
				}

				X86RegAllocRelease( X86::ECX );
		}
}

void X86Translator::encodeFST(){
		XTRegNum	src	= inst->getOperand(1).reg;
		BlockSize	size	= inst->getOperand(2).size;
		XTRegNum	reg	= inst->getOperand(3).reg;
		XTInt32	disp	= inst->getOperand(4).imm;
		X86RegAllocReserve(X86::ECX);
		//20 is magic
		//XTRegNum srcreg = regAllocForceExcept(20, X86::ESP, DEF);
		XTRegNum dstReg = X86RegAllocForceExcept( reg, X86::ESP, USE);

		XTMemAddr src_addr = src_state->fpGet(src);

		if(size == WORD){
				//XTInt32 * src_addr = allocfpWord(src_state->fpReg(src));
				//X86::fpPushFreg32((XTMemAddr)src_addr);
				/*	X86::fpPushFreg32(src_state->fpGet(src));
				//X86::fpPopFreg32(addr);
				if (reg !=0)
				X86::fpPopFreg32_base_disp(srcreg, disp);
				else
				X86::fpPopFreg32((XTMemAddr)disp);
				 */
				X86::movwMemToReg( src_addr, X86::ECX);

				if(reg == 0 )
				{
						X86::movRegToMem( X86::ECX, size, (XTMemAddr)disp);
				}
				else
				{
						X86::movRegToMem( X86::ECX, size, dstReg, disp);
				}
		}
		else{
				X86::movwMemToReg( src_addr, X86::ECX );

				if( reg == 0 )
				{
						X86::movRegToMem( X86::ECX, WORD, (XTMemAddr)disp );
						X86::movwMemToReg( src_addr + 4, X86::ECX );
						X86::movRegToMem( X86::ECX, WORD, (XTMemAddr)(disp + 4));
				}
				else
				{
						X86::movRegToMem( X86::ECX, WORD, dstReg, disp );
						X86::movwMemToReg( src_addr + 4,  X86::ECX );
						X86::movRegToMem( X86::ECX, WORD, dstReg, disp +4);
				}	    
				//DWord * src_addr = allocfpDword(src_state->fpReg(src));
				//X86::fpPushFreg64((XTMemAddr)src_addr);
				/*   	X86::fpPushFreg64(src_state->fpGet(src));
						if (reg != 0)
						X86::fpPopFreg64_base_disp(dstReg, disp);
						else
						X86::fpPopFreg64((XTMemAddr)disp);
				 */
		}
		X86RegAllocRelease(X86::ECX);
}

void X86Translator::encodeFMOV(){
}

void X86Translator::encodeFADDS(){
		X86::fpAdd32();
}

void X86Translator::encodeFADDD(){
		X86::fpAdd64();
}

void X86Translator::encodeFSUBS(){
		X86::fpSub32();
}

void X86Translator::encodeFSUBD(){
		X86::fpSub64();
}

void X86Translator::encodeFMULS(){
		X86RegAllocReserve(X86::ECX);
		XTMemAddr temp_addr = src_state->fpGet( 33 ); //PISAState::$fcw );

		X86::fstcw( temp_addr );

		X86::movMemToReg( temp_addr, HALFWORD, X86::ECX );

		// Set to round nearest	
		X86::andImmToReg( 0xf3ff, X86::ECX );
		//X86::and_immToReg( 0xf7ff, X86::ECX );
		//X86::or_immToReg( 0xc00, X86::ECX );
		X86::movRegToMem( X86::ECX, HALFWORD, temp_addr );

		X86::fldcw( temp_addr );

		X86RegAllocRelease(X86::ECX);

		X86::fpMult32();
}

void X86Translator::encodeFMULD(){
		X86RegAllocReserve(X86::ECX);
		XTMemAddr temp_addr = src_state->fpGet( 33 ); //PISAState::$fcw );

		X86::fstcw( temp_addr );

		X86::movMemToReg( temp_addr, HALFWORD, X86::ECX );

		// Set to round nearest	
		X86::andImmToReg( 0xf3ff, X86::ECX );
		//X86::and_immToReg( 0xf7ff, X86::ECX );
		//X86::or_immToReg( 0xc00, X86::ECX );
		X86::movRegToMem( X86::ECX, HALFWORD, temp_addr );

		X86::fldcw( temp_addr );

		X86RegAllocRelease(X86::ECX);

		X86::fpMult64();
}

void X86Translator::encodeFDIVS(){
		X86RegAllocReserve(X86::ECX);
		XTMemAddr temp_addr = src_state->fpGet( 33 ); //PISAState::$fcw );

		X86::fstcw( temp_addr );

		X86::movMemToReg( temp_addr, HALFWORD, X86::ECX );

		// Set to round nearest	
		X86::andImmToReg( 0xf3ff, X86::ECX );
		//X86::and_immToReg( 0xf7ff, X86::ECX );
		//X86::or_immToReg( 0xc00, X86::ECX );
		X86::movRegToMem( X86::ECX, HALFWORD, temp_addr );

		X86::fldcw( temp_addr );

		X86RegAllocRelease(X86::ECX);

		X86::fpDiv32();
}

void X86Translator::encodeFDIVD(){
		X86RegAllocReserve(X86::ECX);
		XTMemAddr temp_addr = src_state->fpGet( 33 ); //PISAState::$fcw );

		X86::fstcw( temp_addr );

		X86::movMemToReg( temp_addr, HALFWORD, X86::ECX );

		// Set to round nearest	
		X86::andImmToReg( 0xf3ff, X86::ECX );
		//X86::and_immToReg( 0xf7ff, X86::ECX );
		//X86::or_immToReg( 0xc00, X86::ECX );
		X86::movRegToMem( X86::ECX, HALFWORD, temp_addr );

		X86::fldcw( temp_addr );

		X86RegAllocRelease(X86::ECX);

		X86::fpDiv64();

}

void X86Translator::encodeFNEGS(){
		X86::fpChs();
}

void X86Translator::encodeFNEGD(){
		X86::fpChs();
}

void X86Translator::encodeFABSS(){
		X86::fabs();
}

void X86Translator::encodeFABSD(){
		X86::fabs();
}

void X86Translator::encodeFSQRTS(){
		X86RegAllocReserve(X86::ECX);
		XTMemAddr temp_addr = src_state->fpGet( 33 ); //PISAState::$fcw );

		X86::fstcw( temp_addr );

		X86::movMemToReg( temp_addr, HALFWORD, X86::ECX );

		// Set to round nearest	
		X86::andImmToReg( 0xf3ff, X86::ECX );
		//X86::and_immToReg( 0xf7ff, X86::ECX );
		//X86::or_immToReg( 0xc00, X86::ECX );
		X86::movRegToMem( X86::ECX, HALFWORD, temp_addr );

		X86::fldcw( temp_addr );

		X86RegAllocRelease(X86::ECX);

		X86::fpSqrt();
}

void X86Translator::encodeFSQRTD(){
		X86RegAllocReserve(X86::ECX);
		XTMemAddr temp_addr = src_state->fpGet( 33 ); //PISAState::$fcw );

		X86::fstcw( temp_addr );

		X86::movMemToReg( temp_addr, HALFWORD, X86::ECX );

		// Set to round nearest	
		X86::andImmToReg( 0xf3ff, X86::ECX );
		//X86::and_immToReg( 0xf7ff, X86::ECX );
		//X86::or_immToReg( 0xc00, X86::ECX );
		X86::movRegToMem( X86::ECX, HALFWORD, temp_addr );

		X86::fldcw( temp_addr );

		X86RegAllocRelease(X86::ECX);

		X86::fpSqrt();
}

void X86Translator::encodeFCMPS(){
		XTMemAddr src_addr1 = src_state->fpGet(inst->getOperand(2).reg);
		XTMemAddr src_addr2 = src_state->fpGet(inst->getOperand(3).reg);
		XTMemAddr dst_addr = src_state->fpGet(inst->getOperand(4).reg);

		X86::fpPushFreg32(src_addr2);
		X86::fpPushFreg32(src_addr1);
		X86::fcmpFpregWithFpregPop();

		XTUint8 tttn = X86::CCENCODINGS[inst->getOperand(1).cc];

		X86RegAllocReserve( X86::EBX );

		X86::setcc(X86::EBX, tttn);
		X86::movRegToMem(X86::EBX, BYTE, dst_addr);

		X86::fincstp();
		X86::fincstp();

		X86RegAllocRelease( X86::EBX );
}

void X86Translator::encodeFCMPD(){
		XTMemAddr src_addr1 = src_state->fpGet(inst->getOperand(2).reg);
		XTMemAddr src_addr2 = src_state->fpGet(inst->getOperand(3).reg);
		XTMemAddr dst_addr = src_state->fpGet(inst->getOperand(4).reg);

		XTUint8 tttn = X86::CCENCODINGS[inst->getOperand(1).cc];

		X86RegAllocReserve(X86::EBX);

		X86::fpPushFreg64(src_addr2);
		X86::fpPushFreg64(src_addr1);
		X86::fcmpFpregWithFpregPop();

		X86::setcc(X86::EBX, tttn);
		X86::movRegToMem(X86::EBX, BYTE, dst_addr);

		X86::fincstp();
		X86::fincstp();

		X86RegAllocRelease( X86::EBX );
}

void X86Translator::encodeFCONV(){
		XTRegNum	src	= inst->getOperand(1).reg;
		BlockSize	src_size	= inst->getOperand(2).size;
		XTRegNum	dst	= inst->getOperand(3).reg;
		BlockSize	dst_size	= inst->getOperand(4).size;

		XTMemAddr src_addr = src_state->fpGet(src);
		XTMemAddr dst_addr = src_state->fpGet(dst);

		if (src_size == FLOAT && dst_size == DOUBLE){
				X86::fpPushFreg32(src_addr);
				X86::fpPopFreg64(dst_addr);}
		else if (src_size == DOUBLE && dst_size == FLOAT){
				X86::fpPushFreg64(src_addr);
				X86::fpPopFreg32(dst_addr);}
		else if (src_size == FLOAT && dst_size == FLOAT){
				X86::fpPushFreg32(src_addr);
				X86::fpPopFreg32(dst_addr);}
		else if (src_size == DOUBLE && dst_size == DOUBLE){
				X86::fpPushFreg64(src_addr); 
				X86::fpPopFreg64(dst_addr);}
		else if (src_size == WORD && dst_size == FLOAT){
				X86::intPushFreg32(src_addr);
				X86::fpPopFreg32(dst_addr);}
		else if (src_size == WORD && dst_size == DOUBLE){
				X86::intPushFreg32(src_addr);
				X86::fpPopFreg64(dst_addr);}
		else if (src_size == FLOAT && dst_size == WORD){

				//set the FPU's control word RC to truncat mode	

				X86RegAllocReserve(X86::ECX);
				XTMemAddr temp_addr = src_state->fpGet( 33 ); //PISAState::$fcw );

				X86::fstcw( temp_addr );

				X86::movMemToReg( temp_addr, HALFWORD, X86::ECX );

				// Set to round nearest	
				X86::andImmToReg( 0xf3ff, X86::ECX );
				//X86::and_immToReg( 0xf7ff, X86::ECX );
				X86::orImmToReg( 0xc00, X86::ECX );
				X86::movRegToMem( X86::ECX, HALFWORD, temp_addr );

				X86::fldcw( temp_addr );

				X86RegAllocRelease(X86::ECX);

				X86::fpPushFreg32(src_addr);
				X86::intPopFreg32(dst_addr);}
		else if (src_size == DOUBLE && dst_size == WORD){
				//set the FPU's control word RC to trancat mode
				X86RegAllocReserve(X86::ECX);
				XTMemAddr temp_addr = src_state->fpGet( 33 ); //PISAState::$fcw );

				X86::fstcw( temp_addr );

				X86::movMemToReg( temp_addr, HALFWORD, X86::ECX );
				// Set to round nearest
				X86::andImmToReg(0xf3ff, X86::ECX);
				//X86::and_immToReg( 0xf7ff, X86::ECX );
				X86::orImmToReg( 0xc00, X86::ECX );
				X86::movRegToMem( X86::ECX, HALFWORD, temp_addr );

				X86::fldcw( temp_addr );

				X86RegAllocRelease(X86::ECX);

				X86::fpPushFreg64((XTMemAddr)src_addr);
				X86::intPopFreg32(dst_addr);}
		else if (src_size == WORD && dst_size == WORD){
				X86::intPushFreg32((XTMemAddr)src_addr);
				X86::intPopFreg32(dst_addr);}
}

void X86Translator::encodeFINCSTP()
{
		X86::fincstp();
}

XTInt32 * X86Translator::allocFpWord(XTInt32 src){
		fp_word_cache[fp_word_count]=src;
		return &fp_word_cache[fp_word_count++];
}

XTInt64 * X86Translator::allocFpDword(XTInt64 src){
		fp_dword_cache[fp_dword_count]=src;
		return &fp_dword_cache[fp_dword_count++];
}
